protoc 的使用
官网这个 protoc 的使用方式介绍写的实在是模糊,这里重新整理一下
编写一个 Proto 文件
syntax = "proto3";
package tutorial;
import "google/protobuf/timestamp.proto";
option go_package = "github.com/protocolbuffers/protobuf/examples/go/tutorialpb";
版本的变化
官方在 Protocol Buffers v3.0.0 里介绍了,列举了 proto3 的改变:
- 移除了原始值字段的出现逻辑。
- 移除了 required 字段
- 移除了缺省值
- 移除了 unknown 字段 (3.5中又加上了)
- 移除了扩展,使用 Any 代替
- 修复了未知的枚举值的语义
- 添加了 map 类型
- 添加了一些标准类似,比如 time、动态数据的呈现
- 可以使用 JSON 编码代替二进制 proto 编码
安装 protoc
安装编译器,参考 Protocol Buffer Compiler Installation
# 最简单的方式
sudo apt install -y protobuf-compiler
也可以选择手动安装 官方资源库:
# 这里可以只下载对应的编译器的
wget https://github.com/protocolbuffers/protobuf/releases/download/v3.19.1/protoc-3.19.1-linux-x86_64.zip
unzip protoc-3.19.1-linux-x86_64.zip -d protobuf-3.19.1/
# 添加这个执行文件
vim ~/.bashrc
export PROTOBUF=/home/alsritter/tool/go/protobuf-3.19.1/
export PATH=$PATH:$GOROOT/bin:$GOPATH/bin:$PROTOBUF/bin
# 更新
source ~/.bashrc
# 检查是否安装完成
protoc --version
编译为 Go
用 protoc 来编译 .proto 文件为 go 语言,为了支持编译为 go,需要安装 protoc-gen-go 插件,C# 可以安装 protoc-gen-zsharp 插件。
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
这个 go_out 的使用参考官方文档 Go Generated Code
在命令行上可以使用 M${PROTO_FILE}=${GO_IMPORT_PATH}
指定 Go 导入路径
protoc --proto_path=src \
--go_opt=Mprotos/buzz.proto=example.com/project/protos/fizz \
--go_opt=Mprotos/bar.proto=example.com/project/protos/foo \
protos/buzz.proto protos/bar.proto
例如上面就是告诉编译器,遇到 protos/buzz.proto
就去 example.com/project/protos/fizz
目录里面找
编译命令
$ protoc --help
Usage: protoc [OPTION] PROTO_FILES
-IPATH, --proto_path=PATH 指定搜索路径
--plugin=EXECUTABLE:
....
--cpp_out=OUT_DIR Generate C++ header and source.
--csharp_out=OUT_DIR Generate C# source file.
--java_out=OUT_DIR Generate Java source file.
--js_out=OUT_DIR Generate JavaScript source.
--objc_out=OUT_DIR Generate Objective C header and source.
--php_out=OUT_DIR Generate PHP source file.
--python_out=OUT_DIR Generate Python source file.
--ruby_out=OUT_DIR Generate Ruby source file
@<filename> proto文件的具体位置
常用的 flag 介绍:
--proto_path
或者-I
指定 protoc 的搜索 import 的 proto 的文件夹。--go_out
:参数之间用逗号隔开,最后用冒号来指定代码目录架构的生成位置--go_out=plugins=grpc
:参数来生成 gRPC 相关代码,如果不加 plugins=grpc,就只生成 message 数据
其中:
--go_out=plugins=grpc,paths=import:.
。注意一下 paths 参数,他有两个选项,import 和 source_relative 。默认为 import ,代表按照生成的 go 代码的包的全路径去创建目录层级,source_relative 代表按照 protobuf 源文件的目录层级去创建 go 代码的目录层级,如果目录已存在则不用创建
# 这里就是读取 protos 目录下的 proto 文件
protoc -I . --go_out=plugins=grpc:. --go_opt=paths=source_relative protos/*.proto
# 把 Proto 生成的文件生成到 hello_proto 目录下面,主要需要有这个文件才行
protoc -I ./protos --go_out=plugins=grpc:./hello_proto --go_opt=paths=source_relative protos/*.proto
其实很简单,看最后一个参数,例如 protos/*.proto
的前面是空格,就是表示目标 proto 文件的位置,前面的 flag 则是指定生成的位置
实例
# 进入到 proto 目录中,输入
$ protoc *.proto --go_out=plugins=grpc:. --go_opt=paths=source_relative
# 或者在项目的根目录输入
# --go_opt=paths=source_relative 表示要用相对路径产生
$ protoc -I <src_proto_folder> --go_out=plugins=grpc:<dist_directory> --go_opt=paths=source_relative <src_proto_file_path>
$ protoc -I proto/jubox --go_out=plugins=grpc:proto/jubox --go_opt=paths=source_relative proto/jubox/jubox.proto
# 產生編譯檔(產生一般的 .pb.go 檔,但沒有使用 gRPC plugin
$ protoc -I=$SRC_DIR --go_out=$DST_DIR $SRC_DIR/addressbook.proto # 預設根據 go_package 路徑
# 產生 proto 檔,預設將根據 proto 中的 go_package 路徑
$ protoc -I=$SRC_DIR --go_out=$DST_DIR $SRC_DIR/addressbook.proto
# 另一種寫法會 build 出兩隻檔案,一支是 proto buffer(foobar.pb.go),一支是 gRPC 用的檔案(foobar_grpc.pb.go)
$ protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative {proto_filename}.proto